/*
 * Copyright [2011] [Ambud Sharma/ODep Monitor]

   Licensed under the Apache License, Version 2.0 (the "License");

   you may not use this file except in compliance with the License.

   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software

   distributed under the License is distributed on an "AS IS" BASIS,

   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

   See the License for the specific language governing permissions and

   limitations under the License.
 */
package edu.uwsp.orion.odepm.main.client;

import java.util.Collections;
import java.util.Comparator;
import java.util.Random;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.visualization.client.AbstractDataTable.ColumnType;
import com.google.gwt.visualization.client.DataTable;
import com.google.gwt.visualization.client.LegendPosition;
import com.google.gwt.visualization.client.VisualizationUtils;
import com.google.gwt.visualization.client.visualizations.Gauge;
import com.google.gwt.visualization.client.visualizations.corechart.AxisOptions;
import com.google.gwt.visualization.client.visualizations.corechart.LineChart;
import com.google.gwt.visualization.client.visualizations.corechart.Options;
import com.google.gwt.visualization.client.visualizations.corechart.PieChart;
import com.google.gwt.visualization.client.visualizations.corechart.PieChart.PieOptions;

import edu.uwsp.orion.odepm.main.shared.NodeDetails;
import edu.uwsp.orion.odepm.main.shared.NodeMonitorInfo;

import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Position;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.MouseOverHandler;
import com.google.gwt.event.dom.client.MouseOverEvent;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.ColumnSortEvent.ListHandler;
import com.google.gwt.user.cellview.client.TextColumn;

import edu.uwsp.orion.odepm.main.shared.JobSummary;

public class NodeViewer extends DialogBox {

	private ListHandler<JobSummary> sortHandler = new ListHandler<JobSummary>(Collections.<JobSummary>emptyList());
	
	DialogBox box;
	DataTable cpu_memory_network,dtDiskUsage,dtTemperature;
	LineChart cpu_chart;
	PieChart chartDiskUsage;
	Gauge gauge;
	Options options;
	PieChart.PieOptions optionsDisk;
	Gauge.Options optionsTemperature;
	String nodeIP,name;
	
	public NodeViewer(NodeDetails details) {
		nodeIP=details.nodeIp;
		name=details.name;
		setSize("704px", "503px");
		box=this;
		VerticalPanel verticalPanel = new VerticalPanel();
		this.add(verticalPanel);
		verticalPanel.setSize("680px", "475px");
		
		AbsolutePanel apNodeInfoHeader = new AbsolutePanel();
		apNodeInfoHeader.setStyleName("nodeinfoheader");
		verticalPanel.add(apNodeInfoHeader);
		apNodeInfoHeader.setSize("680px", "22px");
		
		Label label = new Label(details.location.replace("/","")+":"+details.nodeIp);
		label.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_CENTER);
		label.setStyleName("gwt-Node-Info-Header");
		apNodeInfoHeader.add(label, 195, 0);
		label.setSize("288px", "22px");
		
		Label lblX = new Label("X");
		lblX.addMouseOverHandler(new MouseOverHandler() {
			public void onMouseOver(MouseOverEvent event) {
				DOM.setStyleAttribute(box.getElement(),"cursor", "hand");
			}
		});
		lblX.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				box.hide();
				box.clear();				
			}
		});
		lblX.setStyleName("gwt-Node-Info-Header");
		apNodeInfoHeader.add(lblX, 662, 0);
		lblX.setSize("19px", "22px");
		
		AbsolutePanel absolutePanel_1 = new AbsolutePanel();
		apNodeInfoHeader.add(absolutePanel_1, 0, 1);
		absolutePanel_1.setStyleName("node-status-color");
		absolutePanel_1.setSize("19px", "21px");
		
		AbsolutePanel apNodeInfoContainer = new AbsolutePanel();
		apNodeInfoContainer.setStyleName("body-nodeinfo-background");
		verticalPanel.add(apNodeInfoContainer);
		apNodeInfoContainer.setSize("679px", "451px");
		
		final AbsolutePanel apNodeCPU = new AbsolutePanel();
		apNodeCPU.setStyleName("standardBorder");
		apNodeInfoContainer.add(apNodeCPU, 0, 0);
		apNodeCPU.setSize("680px", "248px");
		
		final AbsolutePanel apDiskInfo = new AbsolutePanel();
		apNodeInfoContainer.add(apDiskInfo, 481, 250);
		apDiskInfo.setStyleName("standardBorderDisk");
		apDiskInfo.setSize("196px", "199px");
		
		AbsolutePanel apMotherBoard = new AbsolutePanel();
		apMotherBoard.setStyleName("none");
		apNodeInfoContainer.add(apMotherBoard, 102, 251);
		apMotherBoard.setSize("88px", "79px");
		
		AbsolutePanel absolutePanel = new AbsolutePanel();
		absolutePanel.setStyleName("standardBorder");
		apNodeInfoContainer.add(absolutePanel, 211, 250);
		absolutePanel.setSize("269px", "201px");
		
		CellTable<JobSummary> cellTable = new CellTable<JobSummary>();
		absolutePanel.add(cellTable, 0, 0);
		cellTable.setSize("269px", "199px");
		cellTable.setFocus(false);	
		cellTable.setLoadingIndicator(new Image("images/CloseIcon.png"));
		
		TextColumn<JobSummary> jobIDColumn = new TextColumn<JobSummary>() {
		      @Override
		      public String getValue(JobSummary object) {
		        return object.jobID.substring(0, object.jobID.length()-6)+"..";
		      }
		    };		
		
		jobIDColumn.setCellStyleNames(".JobTableHeaderText");
		jobIDColumn.setSortable(true);
		cellTable.addColumn(jobIDColumn, "ID");		
		cellTable.setColumnWidth(jobIDColumn, "85px");
		sortHandler.setComparator(jobIDColumn, new Comparator<JobSummary>() {
			public int compare(JobSummary o1, JobSummary o2) {
				return o1.jobID.compareTo(o2.jobID);
			}
		});		
		
		TextColumn<JobSummary> jobMapColumn = new TextColumn<JobSummary>() {
		      @Override
		      public String getValue(JobSummary object) {
		        return object.mapProgress+"";
		      }
		    };
		
		cellTable.addColumn(jobMapColumn, "Map");
		cellTable.setColumnWidth(jobMapColumn, "80px");
		
		TextColumn<JobSummary> jobreduceColumn = new TextColumn<JobSummary>() {
		      @Override
		      public String getValue(JobSummary object) {
		        return object.reduceProgress+"";
		      }
		    };
		
		cellTable.addColumn(jobreduceColumn, "Reduce");
		cellTable.setColumnWidth(jobreduceColumn, "77px");
		
		final AbsolutePanel apTemperature = new AbsolutePanel();
		apNodeInfoContainer.add(apTemperature, 10, 251);
		apTemperature.setStyleName("none");
		apTemperature.setSize("86px", "79px");
		
		AbsolutePanel apNodeInfo = new AbsolutePanel();
		apNodeInfoContainer.add(apNodeInfo, 0, 330);
		apNodeInfo.setStyleName("standardBorder-new");
		apNodeInfo.setSize("212px", "121px");
		
		Label lblNewLabel = new Label("Cores:");
		lblNewLabel.setStyleName("gwt-Nodeinfo-commonlabel");
		apNodeInfo.add(lblNewLabel, 10, 34);
		
		Label lblCoreCount = new Label(details.coreCount+"");
		lblCoreCount.setStyleName("gwt-Nodeinfo-commonlabel");
		apNodeInfo.add(lblCoreCount, 73, 34);
		lblCoreCount.setSize("28px", "17px");
		
		Label lblmemPerm = new Label("Memory:");
		lblmemPerm.setStyleName("gwt-Nodeinfo-commonlabel");
		apNodeInfo.add(lblmemPerm, 10, 58);
		
		Label lblTotalMemory = new Label((details.totalMem+"").substring(0, (details.totalMem+"").indexOf(".")+2)+" GB");
		lblTotalMemory.setStyleName("gwt-Nodeinfo-commonlabel");
		apNodeInfo.add(lblTotalMemory, 73, 58);
		lblTotalMemory.setSize("144px", "17px");
		
		Label lblNewLabel_2 = new Label("GFLOPS:");
		lblNewLabel_2.setStyleName("gwt-Nodeinfo-commonlabel");
		apNodeInfo.add(lblNewLabel_2, 107, 34);
		
		Label lblGflops = new Label("0.0");
		lblGflops.setStyleName("gwt-Nodeinfo-commonlabel");
		apNodeInfo.add(lblGflops, 167, 34);
		lblGflops.setSize("41px", "17px");
		
		Label lblNewLabel_3 = new Label("Name:");
		lblNewLabel_3.setStyleName("gwt-Nodeinfo-commonlabel");
		apNodeInfo.add(lblNewLabel_3, 10, 10);
		
		Label lblName = new Label(details.name);
		lblName.setStyleName("gwt-Nodeinfo-commonlabel");
		apNodeInfo.add(lblName, 73, 10);
		lblName.setSize("122px", "17px");
		
		Label lblOs = new Label("OS:");
		lblOs.setStyleName("gwt-Nodeinfo-commonlabel");
		apNodeInfo.add(lblOs, 10, 81);
		
		Label lblOS = new Label("Linux 2.6.35-22-generic");
		lblOS.setStyleName("gwt-Nodeinfo-commonlabel");
		apNodeInfo.add(lblOS, 73, 81);
		lblOS.setSize("132px", "42px");

		Runnable initChartCPU_MEM_NET=new Runnable() {
			
			@Override
			public void run() {
				cpu_memory_network=DataTable.create();
				cpu_memory_network.addColumn(ColumnType.NUMBER, "Percentage CPU");
				cpu_memory_network.addColumn(ColumnType.NUMBER, "Percentage Memory");
				cpu_memory_network.addColumn(ColumnType.NUMBER, "Percentage Network");

				cpu_memory_network.addRows(1);
				cpu_memory_network.setValue(0, 0, 0);
				cpu_memory_network.setValue(0, 1, 0);
				cpu_memory_network.setValue(0, 2, 0);
								
				options=Options.create();
				options.setTitle("CPU  Memory  Network  Usage");
				options.setHeight(apNodeCPU.getElement().getClientHeight());
				options.setWidth(apNodeCPU.getElement().getClientWidth());
				options.setLineWidth(1);				
				options.setLegend(LegendPosition.BOTTOM);
				AxisOptions vAOption=AxisOptions.create();
				vAOption.setMinValue(0);
				vAOption.setMinValue(100);
				options.setVAxisOptions(vAOption);
								
				cpu_chart=new LineChart(cpu_memory_network, options);
				apNodeCPU.add(cpu_chart);
			}
		};
		
		VisualizationUtils.loadVisualizationApi(initChartCPU_MEM_NET, LineChart.PACKAGE);
		
		Runnable initChartDisk=new Runnable() {
			
			@Override
			public void run() {
				dtDiskUsage=DataTable.create();
				dtDiskUsage.addColumn(ColumnType.STRING, "Disk Used");
				dtDiskUsage.addColumn(ColumnType.NUMBER, "Terabytes");
				
				dtDiskUsage.addRows(2);
				dtDiskUsage.setValue(0, 0, "Used");
				dtDiskUsage.setValue(0, 1, 0);
				dtDiskUsage.setValue(1, 0, "Free");
				dtDiskUsage.setValue(1, 1, 100);
				optionsDisk=PieOptions.create();
				optionsDisk.setTitle("Disk Usage");
				optionsDisk.set3D(true);
				optionsDisk.setLegend(LegendPosition.BOTTOM);
				optionsDisk.setHeight(apDiskInfo.getElement().getClientHeight()+20);
				optionsDisk.setWidth(apDiskInfo.getElement().getClientWidth());
				optionsDisk.setColors("red","green");
				
				chartDiskUsage=new PieChart(dtDiskUsage,optionsDisk);
				apDiskInfo.add(chartDiskUsage);
			}
		};
		
		VisualizationUtils.loadVisualizationApi(initChartDisk, PieChart.PACKAGE);
		
		Runnable initTemperatureChart=new Runnable() {
			
			@Override
			public void run() {
				dtTemperature=DataTable.create();
				dtTemperature.addColumn(ColumnType.NUMBER,"CPU(C)");
				
				dtTemperature.addRows(1);
				dtTemperature.setValue(0, 0, 10);
				
				optionsTemperature = Gauge.Options.create();
			    optionsTemperature.setWidth(400);
			    optionsTemperature.setHeight(240);
			    optionsTemperature.setGaugeRange(10, 80);
			    optionsTemperature.setGreenRange(10, 45);
			    optionsTemperature.setYellowRange(45, 60);
			    optionsTemperature.setRedRange(60, 80);
			    optionsTemperature.setHeight(apTemperature.getElement().getClientHeight());
			    optionsTemperature.setWidth(apTemperature.getElement().getClientWidth());
			    
			    gauge=new Gauge(dtTemperature, optionsTemperature);
			    apTemperature.add(gauge);
			}
		};
		
		VisualizationUtils.loadVisualizationApi(initTemperatureChart, Gauge.PACKAGE);
		
		
		Timer cpu_mem_net=new Timer() {
			
			@Override
			public void run() {
				updateCPU_Mem_Net_Temp();
			}
		};
		cpu_mem_net.scheduleRepeating(1000);
		
		Timer diskUpdater=new Timer() {
			
			@Override
			public void run() {
				updateDisk();
			}
		};
		diskUpdater.scheduleRepeating(10000);
		
	}
	
	void updateCPU_Mem_Net_Temp(){
		NodeServiceAsync nodeServiceAsync=GWT.create(NodeService.class);
		nodeServiceAsync.getMonitorInfo(name, new AsyncCallback<NodeMonitorInfo>() {
			
			@Override
			public void onSuccess(NodeMonitorInfo result) {
				if(cpu_memory_network.getNumberOfRows()>50){
					cpu_memory_network.removeRow(0);
				}
				cpu_memory_network.addRows(1);
				cpu_memory_network.setValue(cpu_memory_network.getNumberOfRows()-1, 0, result.cpu);
				cpu_memory_network.setValue(cpu_memory_network.getNumberOfRows()-1, 1, result.memory);
				cpu_memory_network.setValue(cpu_memory_network.getNumberOfRows()-1, 2, result.network);
				cpu_chart.draw(cpu_memory_network,options);
								
				dtTemperature.setValue(0, 0, result.cputemp);
				gauge.draw(dtTemperature,optionsTemperature);
			}
			
			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub
				
			}
		});
	}
	
	void updateDisk(){
		NodeServiceAsync nodeServiceAsync=GWT.create(NodeService.class);
		nodeServiceAsync.diskUsageNode(nodeIP, new AsyncCallback<Float>() {
			
			@Override
			public void onSuccess(Float result) {
				dtDiskUsage.setValue(0, 1, result);
				dtDiskUsage.setValue(1, 1, 100-result);
				chartDiskUsage.draw(dtDiskUsage,optionsDisk);
			}
			
			@Override
			public void onFailure(Throwable caught) {
				// TODO Auto-generated method stub
				
			}
		});
	}	
}
